package com.wt.springsamples.redis;

import com.wt.springsamples.model.SysUser;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Component;


@Component
public class UserCacheService {

    @Autowired
    RedisApi redisApi;


//    @Autowired
//    UserMapper userMapper;

    @CachePut(value="userCache",key = "#user.id",condition = "#user!=null")
    public SysUser add(SysUser sysUser){
        System.out.println("UserCacheService add ");
        return sysUser;
    }

    public SysUser get(Integer userId){
        String redisCacheKey = "userCache:"+userId;
        String lockKey = "lock:userLock:"+userId;

        //DCL重建缓存
        Object object = redisApi.get(String.valueOf(redisCacheKey));
        if(object!=null){
            return (SysUser) object;
        }
        //当userId为非热点数据且发生高并发行为时,不能直接访问数据库，否则回给数据库带来巨大压力
        RLock lock = redisApi.getLock(lockKey);
        try {
            lock.lock();
            Object cacheObject = redisApi.get(String.valueOf(redisCacheKey));
            if(cacheObject!=null){
                return (SysUser) object;
            }
            SysUser sysUser =null; //userMapper.selectById(userId);
//            缓存穿透问题
            if(sysUser ==null){
                redisApi.set(redisCacheKey,new SysUser(),3);
                throw  new RuntimeException("用户不存在！！");
            }
            //重新加载到缓存，并设置过期时间为300秒
            redisApi.set(redisCacheKey, sysUser,300);
            return sysUser;
        }finally {
            lock.unlock();
        }
    }

    //单例模式DCL，双重校验加锁
    public  static  class  Singleton{
        private volatile  static Singleton instance;

        private Singleton(){}

        public static Singleton getInstance(){
            if(instance==null){
                synchronized (Singleton.class){
                    if(instance==null){
                        instance =new Singleton();
                    }
                }
            }
            return instance;
        }

    }
}
